package com.hqd.ch03.v14.beans.property.support;

import com.hqd.ch03.v14.beans.property.PropertyAccessor;
import com.hqd.ch03.v14.beans.support.TypeConverterSupport;
import com.hqd.ch03.v14.config.PropertyValue;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements PropertyAccessor {
    /**
     * bean对象
     */
    protected Object bean;
    protected Class<?> beanClass;

    public AbstractPropertyAccessor(Object bean) {
        this.bean = bean;
        this.beanClass = bean.getClass();
    }

    @Override
    public void setPropertyValue(PropertyValue pv) {
        setPropertyValue(pv.getName(), pv.getValue(), pv.isRef());
    }

    protected boolean checkType(String propertyName, Object value) {
        if (value == null) {
            return true;
        }
        Class<?> targetClass = value.getClass();
        Class<?> propertyType = getPropertyType(propertyName);
        return propertyType.isAssignableFrom(targetClass);

    }

    @Override
    public void setPropertyValue(String propertyName, Object value, boolean isRef) {
        Object newVal = value;
        Class<?> propertyType = getPropertyType(propertyName);
        if (isRef) {
            if (!checkType(propertyName, value)) {
                throw new RuntimeException(String.format("%s is not  subclass of %s", value, propertyName));
            }
        } else {
            newVal = convertIfNecessary(value, propertyType);
        }
        try {
            PropertyDescriptor pd = new PropertyDescriptor(propertyName, beanClass);
            Method methodName = pd.getWriteMethod();
            methodName.invoke(bean, newVal);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public Class<?> getPropertyType(String propertyName) {
        try {
            PropertyDescriptor pd = new PropertyDescriptor(propertyName, beanClass);
            return pd.getPropertyType();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object getPropertyValue(String propertyName) {
        try {
            PropertyDescriptor pd = new PropertyDescriptor(propertyName, beanClass);
            return pd.getReadMethod().invoke(bean);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
